import { networkOnline } from '../config';
import store from "@/store/index.js";
import { OPT_GET, OPT_SAVE, OPT_UPDATE, OPT_DELETE, OPT_CALL } from "./config/common.js";
import { apiDataMapping as cacheApiMapping } from './config/doCache.js'
import { apiDataMapping as saveApiMapping } from './config/doSave.js'
import { apiDataMapping as getApiMapping } from './config/doGet.js'
import { apiDataMapping as delApiMapping } from './config/doDelete.js'
import { offlineResponse } from "../index"; 
import { OPT_CACHE, LOG_LEVEL } from './config/common';
// #ifdef APP-PLUS
import { DB } from "@/utils/offline/sqlite/dbinit.js";
// #endif

/** 数据库操作对象 */
// const DB = store.getters.getDB;


/**
 * 在线时，从服务端正常获取接口数据；离线时，从本地文件读取当前api之前返回过的数据
 * @param {Object} api API函数
 * @param {Object} param API函数所需的参数信息
 */
export async function doGet(api, param) {
	if (await networkOnline()) {
		// 正常请求
		return api(param);
	} 
	else {
		try {
			const config = getApiMapping.get(api);
			if(!config) {
				console.error('ingoreNetGet api 未配置')
				return
			}
			const { 
				type, where, tableName, 
				children, dataFieldName, 
				single, resultMapping, combin
			} = config
			
			// 判断请求
			if(type !== OPT_GET) {
				return;
			}
			
			// 执行...
			const condition = where(param);
			let dataArray = await DB.select(`select * from ${tableName} where ${condition};`);

			// 判断是否有children
			if(Array.isArray(children)) {
				for(let i = 0; i < children.length; i++) {
					for(let j = 0; j < dataArray.length; j++) {
						const fieldName = children[i].fieldName;
						dataArray[j][fieldName] = await doGetChildren(children[i], dataArray[j]);
					}
				}
			}
			if(resultMapping) {
				for(let i=0;i<dataArray.length;i++) {
					dataArray[i] =  await resultMapping(dataArray[i])
				}
			}
			
			
			if(single){
				dataArray = dataArray[0]
			}
			if(combin && (combin instanceof Function)) {
				dataArray = combin(dataArray)
			}
			
			return offlineResponse(dataFieldName ? {[dataFieldName]:dataArray} : dataArray);
		} catch (err) {
			return offlineResponse(false, false, err.message);
		}
	}
}

/**
 * 在线时，从服务端正常获取接口数据；离线时，从本地文件读取当前api之前返回过的数据
 * @param {Object} param API函数所需的参数信息
 */
export async function doGetChildren(config, parent) {
	try {
		const { tableName, fnCondition, single } = config;
		
		const childData =  await DB.select(`
			select * 
			  from ${tableName} 
			 where ${fnCondition(parent)}
			 ${single ? 'limit 1' : ''}
			;`
		)
		return childData.length > 0
					? single
						? childData[0] 
						: childData
					: null;
	} catch (err) {
		return [];
	}
}
/**
 * 缓存数据
 */
export async function doCache(api, param){
	const apiName = api.name || api
	const config = cacheApiMapping.get(api);
	if(!config) {
		console.error(`[doCache][${apiName}][error] api 未配置`)
		return
	}
	if (!(await networkOnline())) {
		console.error(`[doCache][${apiName}][error]暂无网络连接,无法完成数据缓存`);
		return
	}
	
	try {
		const {name, type, dataFieldName='result', persisApi} = config;
		// 判断操作类型
		
		if(type !== OPT_CACHE) return;
		
		const resp = await api(param)
		if(!resp.success) {
			warn(`[doCache][${apiName}] 缓存[${name}]数据时，获取返回结果错误: ${resp.message}`);
			return
		}
		let respData = resp[dataFieldName]
		if(dataFieldName!=='result'){
			respData = resp['result'][dataFieldName]
		}
		warn(`[doCache][${apiName}] 缓存[${name}]数据时，获取到的返回数据`,respData);
		const persisList = Array.isArray(respData) ? respData : [respData]
		for(const item of persisList){
			await doSave(persisApi, item, true)
		}
		return respData
	} catch (err) {
		console.error(`[doCache][${apiName}][error]`, param, err)
		return err;
	}
}

/**
 * 在线时，将表单数据提交到服务端；离线时，将表单数据写入到本地文件进行持久化，以便在网络恢复后再提交到服务器
 * @param {Object} api API函数
 * @param {Object} param API函数所需的参数信息
 * @param {Boolean} keepPersistence 是否保持网络链接
 */
export async function doSave(api, param, keepPersistence=false){
	if (!keepPersistence && (await networkOnline())) {
		// 正常请求
		return api(param);
	}
	
	const apiName = api.name || api
	const config = saveApiMapping.get(api);
	if(!config) {
		errLog(`[doSave][${apiName}][error] api 未配置`)
		return
	}
	try {
		const { 
			type, tableName, exclude, 
			fields, children, beforeActions, afterAction, resultMapping
		} = config;

		// 判断请求
		if(type !== OPT_SAVE) {
			return;
		}
		
		// 前置操作
		if(Array.isArray(beforeActions)){
			for(const beforeAction of beforeActions){
				if(beforeAction && beforeAction.required) {
					const {type, method, required} = beforeAction
					const needToDo = required(param)
					debug('doSave[beforeAction][needToDo]', needToDo)
					if(needToDo){
						debug(`doSave[beforeAction][${type}]`)
						if(type===OPT_CALL) {
							const actionResult = method(param)
							console.log('actionResult', actionResult);
							console.log('结果',await actionResult);
							param = actionResult.then ? await actionResult : actionResult
						}
						//TODO: 支持其他类型的前置操作
					}
				}
			}
		}
		
		let savingRecordFields = {}
		//是否配置了fields函数
		if(fields) {
			const fs = fields(param)
			savingRecordFields = fs.then ? (await fs) : fs
		}else {
			savingRecordFields = param
		}
		
		let fNames = Object.keys(savingRecordFields)
		let dataId = null
		
		// 排除不需要保存入库的字段
		if(Array.isArray(exclude)){
			fNames = fNames.filter(prop=>!exclude.some(ex=>prop===ex))
		}
		if(fNames.length > 0) {
			const fValues = fNames.map(item => savingRecordFields[item]);
			for(let i = 0; i < fValues.length; i++) {
				if(typeof fValues[i] === "string") {
					fValues[i] = `'${fValues[i]}'`;
				}else if(Array.isArray(fValues[i])) {
					fNames.splice(i, 1);
					fValues.splice(i, 1);
					i--;
				}else if(typeof fValues[i] === 'boolean'){
					fValues[i] = fValues[i] === true ? 1 : 0
				}else if(fValues[i] === undefined || fValues[i] === null) {
					fValues[i] = `''`;
				}
			}

			let idIdx = fNames.findIndex(item=>item==='id')
			dataId = (idIdx === -1 ? null : fValues[idIdx])
			
			let _id = null
			// doCache调用时不做更新
			if(!keepPersistence && dataId){
				debug(`doCache 调用  doSave`)
				//更新记录
				const setClause = fNames.map((item, index) => `${item}=${fValues[index]}`).join(",");
				let updateSql = `
					update ${tableName} 
					   set ${setClause} 
					 where id = ${savingRecordFields['id']};`
				debug(`doSave[${apiName}][update][${tableName}] sql:`,updateSql )
				
				if(api.name === 'diseaseOrderSave') {
					console.log(param.version, param.code, param.submit);
					console.warn(updateSql);
				}
				
				await DB.execute(updateSql)
				if(fNames.find(n=>n==='version')){
					let updateVersionSql = `
						update ${tableName} 
						   set version=version+1
						 where id = ${savingRecordFields['id']};`
					debug(`doSave[${apiName}][updateVersion][${tableName}] sql:`,updateVersionSql)
					
					await DB.execute(updateVersionSql)
				}
			} else {				
				// 新增记录
				// 生成唯一标识符
				if(!keepPersistence){
					// 离线期间新增的本地数据
					dataId = (0 -await DB.createId()) // 创建一个新的id(本地)
					fNames.unshift('_id', "id")
					fValues.unshift("''", dataId) // _id为''
				} else{
					// 被 doCache调用时，_id和待缓存数据原有的id属性值相等
					_id = `'${dataId}'`
					fNames.unshift("_id")
					fValues.unshift(_id)
				}
				//如果传入的数据只有id 和 _id 两个字段，则不做插入操作(无意义)
				if(fNames.length > 2) {
					const insertSql = `insert or replace into ${tableName} (${fNames.join(",")}) values (${fValues.join(",")});`
					// if(fNames.find(n=>n==='version')){
					// 	let updateVersionSql = `
					// 		update ${tableName} 
					// 		   set version=version+1
					// 		 where id = ${savingRecordFields['id']};`
					// 	debug(`doSave[${apiName}][updateVersion][${tableName}] sql:`,updateVersionSql)
						
					// 	await DB.execute(updateVersionSql)
					// }
					// if(api.name === 'diseaseOrderSave') {
					// 	console.log(param.version, param.code, param.submit);
					// 	console.warn(insertSql);
					// }
					debug('[doSave][${apiName}]insertSql',`[${tableName}]`, insertSql)   
					await DB.execute(insertSql)
				}				
			}
		}
		
		
		// 判断是否有children
		if(Array.isArray(children)) {
			debug(`doSave[${apiName}][SaveChildren][length]:`,children.length)
			for(const childConfig of children) {
				await doSaveChildren(childConfig, param, dataId);
			}
		}
		
		//后置操作调用
		if(afterAction && afterAction.required && dataId) {
			const needToDo = afterAction.required(param)
			if(!needToDo) return
			debug(`doSave[${apiName}][afterAction][${afterAction.type}]dataId:`,dataId )
			await afterSave(afterAction, param, dataId)
		}
		let result  = null
		if(fNames.length > 2) {
			let selectSavedRecordSql = `select * from ${tableName} where id=${dataId} limit 1`
			debug(`doSave[${apiName}][selectSavedRecordSql]:`, selectSavedRecordSql)
			const savedRecord = await DB.select(selectSavedRecordSql)
			result = savedRecord[0]
		}
		resultMapping && (result = resultMapping(result, param, DB))
		return offlineResponse(result && result.then ? (await result) : result)
		
	} catch (err) {
		errLog(`[doSave][${apiName}][Error]`, param, err)
		return offlineResponse(false, false, err.message);
	}
}

/**
 * @param {Object} afterActionConfig
 * @param {Object} preParam
 */
export async function afterSave(afterActionConfig, preParam, preId) {
	if(!afterActionConfig) {
		console.error('afterActionConfig 未配置')
		return
	}
	const {type, api, param} = afterActionConfig
	if(!type) {
		console.error('afterActionConfig.type 未配置, 未执行后置操作')
		return
	}
	// 判断后置操作类型: OPT_SAVE | OPT_DELETE
	if (type !== OPT_SAVE && type !== OPT_DELETE) {
		console.error(`afterActionConfig.type=${type}不符合预期[OPT_SAVE | OPT_DELETE], 未执行后置操作`)
		return    
	}
	
	if(type===OPT_SAVE) {
		const actionConfig = saveApiMapping.get(api)
		if(!actionConfig) {
			console.error(`afterAction.api未匹配到对应的后置操作, 未执行后置操作`)
			return
		}
		let afterActionParam = param(preParam, preId)
		// 如果param是一个异步函数,需要等待到异步执行的结果才能继续进行
		if(afterActionParam.then) {
			afterActionParam = await afterActionParam
		}
		await doSave(api, afterActionParam)
	}
	
	//TODO: 增加 type===OPT_DELETE 时的处理逻辑
}


//TODO: 保存二级数据时也需要考虑新增和修改的情况
/**
 * 在线时，将表单数据提交到服务端；离线时，将表单数据写入到本地文件进行持久化，以便在网络恢复后再提交到服务器
 * @param {Object} param API函数所需的参数信息
 */
export async function doSaveChildren(config, parent, pid) {
	try {
		if(!config) {
			console.error('doSaveChildren api 未配置')
			return
		}
		const { tableName, fields, exclude } = config;
		
		const savingData = fields(parent);
		warn('[doSaveChildren][savingData]', savingData)
		//没有需要保存入库的二级数据，直接返回
		if(!savingData) return
		const savingDataList = !Array.isArray(savingData) ? [savingData] : savingData
		
		for(const item of savingDataList) {
			const fNames = Object.keys(item);
			// 排除不需要保存入库的字段
			if(Array.isArray(exclude)){
				fNames = fNames.filter(prop=>!exclude.some(ex=>prop===ex))
			}
			const fValues = fNames.map(prop => item[prop]);
			
			for(let i = 0; i < fValues.length; i++) {
				if(typeof fValues[i] === "string") {
					fValues[i] = `'${fValues[i]}'`;
				}else if(typeof fValues[i] === 'boolean'){
					fValues[i] = fValues[i] === true ? 1 : 0
				}else if(fValues[i] === undefined || fValues[i] === null) {
					fValues[i] = `''`;
				}
			}
			
			// 生产唯一标识符
			// fNames.unshift("_id", "pid");
			// fValues.unshift(`'${await DB.createId()}'`, pid);
			fNames.unshift("_id");
			fValues.unshift(`'${await DB.createId()}'`);
			await DB.execute(`insert into ${tableName} (${fNames.join(",")}) values (${fValues.join(",")});`)
		}
	} catch (err) {
		//TODO: 抛出错误
		console.error(err)
		// throw new Error(err);
	}
}

/**
 * 删除图片
 * @param {Object} api API函数
 * @param {Object} param API函数所需的参数信息
 */
export async function doDelete(api, param) {
	if ((await networkOnline())) {
		// 正常请求
		return await api(param);
	}
	const config = delApiMapping.get(api);
	const apiName = (typeof api) === 'string'
				? api 
				: (typeof api) === 'function'
					? api.name
					: 'Unknown Incorrect API'
	if(!config) {		
		warn(`[sqlite][doDelete][api=${apiName}] 无对应配置`)
		return
	}
	try {
		const { type, tableName, where, beforeAction } = config
		// 判断请求
		if(type !== OPT_DELETE) {
			return;
		}
		// 前置操作		
		if(beforeAction && beforeAction.required) {
			const {type, method, required} = beforeAction
			const needToDo = required(param)
			debug('[doDelete][beforeAction][needToDo]', needToDo)
			if(needToDo){
				debug(`[doDelete][beforeAction][${type}]`)
				if(type===OPT_CALL) {
					const actionResult = method(param)
					const isContinue = actionResult.then ? (await actionResult) : actionResult
					debug('[doDelete][beforeAction][isContinue]', isContinue)
					if(!isContinue){
						return offlineResponse(true)
					}
				}
			}
		}
			
		if(!where) {
			warn(`[sqlite][doDelete][api=${apiName}] 未配置删除条件，属于危险操作！！`)
			return offlineResponse(true)
		}
		const whereClause = where(param)
		if(!whereClause) {
			warn(`[sqlite][doDelete][api=${apiName}] 未配置删除条件，属于危险操作！！`)
			return offlineResponse(true)
		}
		await DB.execute(`delete from ${tableName} where ${whereClause};`)
		return offlineResponse(true)
	} catch (err) {
		return offlineResponse(false, false, err.message)
	}
}

/**
 * 在线时，将表单数据提交到服务端；离线时，将表单数据写入到本地文件进行持久化，以便在网络恢复后再提交到服务器
 */
export async function doDeleteChildren(config, parent) {
	if(!config) {
		errLog('doSave api 未配置')
		return
	}
	try {
		const { fnCondition, tableName } = config;
		debug(`delete from ${tableName} where ${fnCondition(parent)};`);
		
		await DB.execute(`delete from ${tableName} where ${fnCondition(parent)};`)
	} catch (err) {
		return offlineResponse(false, false, err.message);
	}
}

const logLevelMap = {
	error: 4,
	fatal: 3,
	warn: 2,
	info: 1,
	debug: 0
}

export function fatal(...messages) {
	if(logLevelMap[LOG_LEVEL] <= 3)
	console.warn('[fatal]', ...messages);
}


export function warn(...messages) {
	if(logLevelMap[LOG_LEVEL] <= 2)
	console.warn('[warn]', ...messages);
}

export function info(...messages) {
	if(logLevelMap[LOG_LEVEL] <= 1)
	console.log('[info]', ...messages);
}
export function debug(...messages) {
	if(logLevelMap[LOG_LEVEL] <= 0)
	console.debug('[debug]', ...messages);
}
export function errLog(...messages) {
	console.error(...messages);
}